package com.zjh.document.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.zjh.common.config.SnowflakeConfig;
import com.zjh.common.entity.Response;
import com.zjh.document.entity.Enum.OnlyOfficeCallBackStatus;
import com.zjh.document.entity.OnlyofficeFileInfoDO;
import com.zjh.document.entity.VO.GenerateOfficeConfigParamVO;
import com.zjh.document.service.IOnlyofficeFileInfoService;
import com.zjh.document.service.OnlyOfficeService;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.errors.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Scanner;

@RestController
@Slf4j
@RequestMapping("/documentManager/onlyoffice")
public class OnlyOfficeController {

    @Autowired
    private MinioClient minioClient;

    @Value("${minio.bucket}")
    private String bucketName;

    @Autowired
    private OnlyOfficeService onlyOfficeService;

    @Resource
    private IOnlyofficeFileInfoService onlyofficeFileInfoService;

    @Resource
    private SnowflakeConfig snowflakeConfig;


    // 生成 OnlyOffice 编辑配置
    @PostMapping("/config")
    public Response<String> generateConfig(@RequestBody GenerateOfficeConfigParamVO paramVO) {

        return Response.success(onlyOfficeService.generateConfig(paramVO));
    }

    @RequestMapping("/callback")
    public String callback(@RequestParam("fileName") String fileName,
                           @RequestParam(value = "type", required = false) Boolean type,
                           @RequestParam(value = "path", required = false) String path,
                           HttpServletRequest request,
                           HttpServletResponse response) throws IOException {
        String fullPath = path + fileName;
        log.info("fullPath: " + fullPath);

        Scanner scanner = new Scanner(request.getInputStream()).useDelimiter("\\A");

        String body = scanner.hasNext() ? scanner.next() : "";

        JSONObject jsonObj = JSONObject.parseObject(body);
        if (Objects.isNull(jsonObj)) {
            return "{\"error\":0}";
        }
        log.info("onlyOffice 传入 jsonObj:  --------- \n" + jsonObj);
        int status = (int) jsonObj.get("status");
        log.info("当前文档状态： " + status);
        if (status == OnlyOfficeCallBackStatus.READY_TO_SAVE.getCode() ||
                status == OnlyOfficeCallBackStatus.SAVE.getCode()) {
            String downloadUri = (String) jsonObj.get("url");

            URL url = new URL(downloadUri);
            java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
            InputStream stream = connection.getInputStream();

            //***** 最后一个用户关闭文档后10s后触发 *****
            if (status == OnlyOfficeCallBackStatus.READY_TO_SAVE.getCode()) {

                Integer fileStorageType = type ? 0 : 1;

                QueryWrapper<OnlyofficeFileInfoDO> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("file_storage_type", fileStorageType);
                queryWrapper.eq("absolute_path", path + fileName);
                List<OnlyofficeFileInfoDO> list = onlyofficeFileInfoService.list(queryWrapper);

                OnlyofficeFileInfoDO onlyofficeFileInfoDO = new OnlyofficeFileInfoDO();
                onlyofficeFileInfoDO.setFileKey(onlyOfficeService.getKey(fullPath, true) + '_' + snowflakeConfig.snowflakeId());
                onlyofficeFileInfoDO.setAbsolutePath(fullPath);
                onlyofficeFileInfoDO.setUpdateTime(new Date());

                if (CollectionUtils.isNotEmpty(list)) {
                    onlyofficeFileInfoService.update(onlyofficeFileInfoDO, queryWrapper);
                } else {
                    onlyofficeFileInfoDO.setId(snowflakeConfig.snowflakeId());
                    onlyofficeFileInfoDO.setFileStorageType(fileStorageType);
                    onlyofficeFileInfoService.save(onlyofficeFileInfoDO);
                }
            }

            try {
                if (type) {
                    minioClient.putObject(
                            PutObjectArgs.builder()
                                    .bucket(bucketName)
                                    .object(fileName)
                                    .stream(stream, -1, 10485760) // 10MB 分片
                                    .build());
                    log.info("尝试保存到Minio 结束无报错");
                } else {
                    String pathName = path + "/" + fileName;
                    log.info("尝试保存到本地: " + pathName);

                    File fileToSave = new File(pathName);
                    if (!fileToSave.exists()) {   //文件不存在则创建文件，先创建目录
                        File dir = new File(fileToSave.getParent());
                        dir.mkdirs();
                        fileToSave.createNewFile();
                    }
                    try (FileOutputStream out = new FileOutputStream(fileToSave)) {//默认覆盖
                        int read;
                        final byte[] bytes = new byte[1024];
                        while ((read = stream.read(bytes)) != -1) {
                            out.write(bytes, 0, read);
                        }

                        out.flush();
                    }
                    log.info("尝试保存到本地 结束无报错");
                }

            } catch (ErrorResponseException e) {
                throw new RuntimeException(e);
            } catch (InsufficientDataException e) {
                throw new RuntimeException(e);
            } catch (InternalException e) {
                throw new RuntimeException(e);
            } catch (InvalidKeyException e) {
                throw new RuntimeException(e);
            } catch (InvalidResponseException e) {
                throw new RuntimeException(e);
            } catch (NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
            } catch (ServerException e) {
                throw new RuntimeException(e);
            } catch (XmlParserException e) {
                throw new RuntimeException(e);
            }

            connection.disconnect();
        }
        return "{\"error\":0}";
    }

}